package util;

import java.util.ArrayList;

import logging.Logger;

import networkInterface.NetworkInterfaceBase;

import object.Connection;
import object.Node;

public class NodeUtil {
	public static void removeAllConnections(ArrayList<Node> nodes){
		for(Node n : nodes){
			for(NetworkInterfaceBase netInt : n.getInterfaces()){
				netInt.removeConnections();
			}
		}
	}
	public static void resetAllNodesColor(ArrayList<Node> nodes){
		for(Node n : nodes){
			n.color = Settings.getInstance().getFrontColor();
		}
	}
	
	public static int mapNetwork( Node root, ArrayList<Node> Network )
	{
		Network.add(root);
		
		for( Connection c : root.getConnections())
		{
			if(c.getN1() == root && Network.contains(c.getN2()) == false)
				mapNetwork(c.getN2(), Network);
			else if (c.getN2() == root && Network.contains(c.getN1()) == false)
				mapNetwork(c.getN1(), Network);			
		}
		
		return Network.size();
	}
	
	public static void removeNode(Node n, ArrayList<Node> nodes){
		for(NetworkInterfaceBase netInt : n.getInterfaces()){
			netInt.removeConnections();
		}
		nodes.remove(n);
	}
	
	/**
	 * @param n - Instance of Type node which is the node that is being connected to
	 * @param connectingInterface - The interface that is trying to negotiate a connection to node n
	 * @return NetworkInterfaceBase - a instance of class NetworkInterfaceBase which the connectingInterface can connect to
	 */
	public static NetworkInterfaceBase removeSingleConnection( Node n, NetworkInterfaceBase connectingInterface ){
		ArrayList<NetworkInterfaceBase> possibleInterfaces = n.getInterfaces();
		int index = 0;
		int size = possibleInterfaces.size();
		
		// go through interfaces to see which ones can connect to the connecting interface
		while( index < size )
		{
			NetworkInterfaceBase target = possibleInterfaces.get(index);
			
			//If an interface is open and able to connect return it.
			if( target.canConnect(connectingInterface) )
				return target;
			
			//We only want to keep interfaces that we cannot connect to because a connection already
			//exists on that network
			if( !target.canConnectWithReason(connectingInterface).equalsIgnoreCase("No connections left") )
			{
				possibleInterfaces.remove(index);
				index--; //Offset the index so we look at all the interfaces in the ArrayList
			}
			index++;
			size = possibleInterfaces.size();
		}
		
		// Gather the nodes that can be connected to by the interfaces that are ineligible
		ArrayList<Node> AlreadyConnected = new ArrayList<Node>();
		AlreadyConnected.add(n);
		for( NetworkInterfaceBase NetInterface : n.getInterfaces() )
		{
			if( !possibleInterfaces.contains(NetInterface) )
			{
				for(Connection c: NetInterface.getConnections())
				{
					if( !AlreadyConnected.contains(c.getN1()))
						mapNetwork(c.getN1(), AlreadyConnected);
					if( !AlreadyConnected.contains(c.getN2()))
						mapNetwork(c.getN2(), AlreadyConnected);
				}
					
			}
				
		}
		
		
		//we now have an ArrayList of nodes we can visit using connections that are unable to connect to our desired interface
		//we also have an ArrayList of interfaces which can connect to the connecting Interface Now the ideal solution would be
		//to find a connection that we can connect to which is redundant to the nodes our connecting interface can't reach.
		
		for( NetworkInterfaceBase target : possibleInterfaces )
		{
			for( Connection c: target.getConnections() )
			{
				if( AlreadyConnected.contains(c.getN1()) && c.getN1() != n )
				{
					try { 
						target.removeConnection(c); 
						return target; }
					catch (Exception e) { 
						Logger.getInstance().log(Logger.WARNING, "RemoveSingleConnection: failed to remove target connection"); }
				}
				if( AlreadyConnected.contains(c.getN2()) && c.getN2() != n )
				{
					try { 
						target.removeConnection(c); 
						return target;}
					catch (Exception e) { 
						Logger.getInstance().log(Logger.WARNING, "RemoveSingleConnection: failed to remove target connection"); }
				}
				if( c.getN1() != n )
					mapNetwork(c.getN1(), AlreadyConnected);
				else if( c.getN2() != n )
					mapNetwork(c.getN2(), AlreadyConnected);
			}
			
		}
		
		// at this point, if there where any redundant connections to networks they would have been removed and connected to the new node
		// we now only want to drop a connection if the network on the connected node is smaller than the new network we are bringing in.
		
		
		
		return null;
	}
	
	public static boolean isValidNodeLocation(Node node, ArrayList<Node> nodes){
		for(Node n : nodes){
			if(n.getLength(node) < 7)
				return false;
		}
		return true;
	}
	
	
	
}
